package com.flyduck.common.util;


import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.flyduck.common.exception.UtilException;
import com.flyduck.common.vo.RouteVO;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * @program: flyduck-platform
 * @description: 树形结构转换工具类
 * @author: flyduck
 * @create: 2021-02-27 11:51
 **/
@Slf4j
public class TreeUtil {

    /**
     * list转成树形结构
     *
     * @param clazz
     * @param dataList
     * @param <T>
     * @return
     */
    public static <T> List<T> toTree(Class<T> clazz, List<T> dataList) {
        TreeNodeConfig treeNodeConfig = TreeNodeConfig.DEFAULT_CONFIG;
        return toTree(
                clazz,
                dataList,
                treeNodeConfig.getIdFieldName(),
                treeNodeConfig.getParentIdFieldName(),
                treeNodeConfig.getChildrenFieldName(),
                treeNodeConfig.getSortFieldName(),
                treeNodeConfig.getRootFlag()
        );
    }


    /**
     * list转成树形结构
     *
     * @param clazz
     * @param dataList
     * @param <T>
     * @return
     */
    public static <T> List<T> toTree(Class<T> clazz, List<T> dataList, TreeNodeConfig treeNodeConfig) {
        return toTree(
                clazz,
                dataList,
                treeNodeConfig.getIdFieldName(),
                treeNodeConfig.getParentIdFieldName(),
                treeNodeConfig.getChildrenFieldName(),
                treeNodeConfig.getSortFieldName(),
                treeNodeConfig.getRootFlag()
        );
    }


    /**
     * list转成树形结构
     *
     * @param clazz
     * @param dataList
     * @param idFieldName
     * @param parentIdFieldName
     * @param childrenFieldName
     * @param sortFieldName
     * @param rootFlag
     * @param <T>
     * @return
     */
    public static <T> List<T> toTree(Class<T> clazz, List<T> dataList, String idFieldName, String parentIdFieldName, String childrenFieldName, String sortFieldName, Object rootFlag) throws UtilException {
        //dataList存在根节点时返回的菜单树
        List<T> treeList = new ArrayList<>();
        //dataList不存在根节点时返回的菜单树
        List<T> notRootTreeList = new ArrayList<>();
        List<Object> ids = new ArrayList<>();
        for (T t : dataList) {
            Object id = ReflectUtil.getFieldValue(t, idFieldName);
            ids.add(id);
        }
        for (T node : dataList) {
            //找出根节点
            Object parentId = ReflectUtil.getFieldValue(node, parentIdFieldName);
            if (rootFlag == null || "".equals(rootFlag)) {
                if (parentId == null || "".equals(parentId)) {
                    treeList.add(node);
                }
            } else {
                if (String.valueOf(rootFlag).equals(String.valueOf(parentId))) {
                    treeList.add(node);
                }
            }

            //设置子节点
            ReflectUtil.setFieldValue(node, childrenFieldName, getChildren(idFieldName, parentIdFieldName, childrenFieldName, sortFieldName, node, dataList));
            CollectionUtil.sortByProperty(treeList, sortFieldName);
            //处理dataList没有一个为根节点的情况,如果没有父级就放到notRootTreeList
            if (!ids.contains(parentId)) {
                notRootTreeList.add(node);
            }
        }
        if (CollectionUtil.isNotEmpty(treeList)) {
            return treeList;
        } else {
            return notRootTreeList;
        }

    }

    /**
     * 获取子节点
     *
     * @param idFieldName
     * @param parentIdFieldName
     * @param childrenFieldName
     * @param sortFieldName
     * @param currentNode
     * @param dataList
     * @param <T>
     * @return
     */
    private static <T> List<T> getChildren(String idFieldName, String parentIdFieldName, String childrenFieldName, String sortFieldName, T currentNode, List<T> dataList) throws UtilException {
        List<T> children = new ArrayList<>();
        for (T node : dataList) {
            Object id = null;
            Object parentId = null;
            id = ReflectUtil.getFieldValue(currentNode, idFieldName);
            parentId = ReflectUtil.getFieldValue(node, parentIdFieldName);
            if (String.valueOf(id).equals(parentId)) {
                ReflectUtil.setFieldValue(node, childrenFieldName, getChildren(idFieldName, parentIdFieldName, childrenFieldName, sortFieldName, node, dataList));
                ReflectUtil.setFieldValue(node, childrenFieldName, getChildren(idFieldName, parentIdFieldName, childrenFieldName, sortFieldName, node, dataList));
                children.add(node);
            }
        }
        CollectionUtil.sortByProperty(children, sortFieldName);
        return children;
    }

    public static void main(String[] args) {
        RouteVO routeVO1 = new RouteVO();
        routeVO1.setId("1");
        routeVO1.setParentId(null);
        routeVO1.setMenuName("系统管理");
        routeVO1.setSort("1");
        RouteVO routeVO2 = new RouteVO();
        routeVO2.setId("2");
        routeVO2.setParentId("1");
        routeVO2.setSort("1");
        routeVO2.setMenuName("用户管理");
        RouteVO routeVO3 = new RouteVO();
        routeVO3.setId("3");
        routeVO3.setParentId("1");
        routeVO3.setSort("1");
        routeVO3.setMenuName("角色管理");
        RouteVO routeVO4 = new RouteVO();
        routeVO4.setId("4");
        routeVO4.setParentId("2");
        routeVO4.setSort("1");
        routeVO4.setMenuName("新增用户");
        RouteVO routeVO5 = new RouteVO();
        routeVO5.setId("5");
        routeVO5.setParentId(null);
        routeVO5.setSort("2");
        routeVO5.setMenuName("日志管理");
        RouteVO routeVO6 = new RouteVO();
        routeVO6.setId("6");
        routeVO6.setParentId("5");
        routeVO6.setSort("2");
        routeVO6.setMenuName("登录日志");
        RouteVO routeVO7 = new RouteVO();
        routeVO7.setId("7");
        routeVO7.setParentId("5");
        routeVO7.setSort("1");
        routeVO7.setMenuName("操作日志");
        List<RouteVO> list = new ArrayList<>();
        list.add(routeVO1);
        list.add(routeVO2);
        list.add(routeVO3);
        list.add(routeVO4);
        list.add(routeVO5);
        list.add(routeVO6);
        list.add(routeVO7);
        List<RouteVO> list1 = null;
        list1 = toTree(RouteVO.class, list);
        log.info("数据[{}]", JSON.toJSONString(list1));


    }

}
